#!/usr/bin/python3
# -*- coding:utf-8 -*-
# __author__ == taoyulong2018@gmail.com
# __time__ == 2023/10/30 9:13
# ===========================================
#       题目名称： 65. 有效数字
#       题目地址： https://leetcode.cn/problems/valid-number/description/
#       题目描述： https://note.youdao.com/s/VjIUrvCDy
# ===========================================


class Solution:
    def isNumber(self, s: str) -> bool:
        SIGN, DIGIT, POINT, E = "符号", "数值", ".", "e"
        STATE = [
            {DIGIT: 1},
            {DIGIT: 1, E: 2, DIGIT: 3},
            {DIGIT: 1, E: 2, SIGN: 4, DIGIT: 5},
            {DIGIT: 1, POINT: 6},
            {DIGIT: 1, POINT: 6, DIGIT: 7},
            {DIGIT: 1, POINT: 6, DIGIT: 7, E: 8, DIGIT: 9},
            [DIGIT, POINT, DIGIT, E, SIGN, DIGIT],
            [DIGIT, POINT, E, DIGIT],
            [DIGIT, POINT, E, SIGN, DIGIT],
            [POINT, DIGIT],
            [POINT, DIGIT, E, DIGIT],
            [POINT, DIGIT, E, SIGN, DIGIT],
            [SIGN, DIGIT],
            [SIGN, DIGIT, E, DIGIT],
            [SIGN, DIGIT, E, SIGN, DIGIT],
            [SIGN, POINT, DIGIT, E, SIGN, DIGIT],
            [SIGN, DIGIT, POINT],
            [SIGN, DIGIT, POINT, DIGIT],
            [SIGN, DIGIT, POINT, DIGIT, E, DIGIT],
            [SIGN, DIGIT, POINT, E, DIGIT],
            [SIGN, POINT, DIGIT],
            [SIGN, POINT, DIGIT, E, DIGIT]
        ]



    def isNumber4(self, s: str) -> bool:
        SIGN, DIGIT, POINT, E = "符号", "数值", ".", "e"
        STATE = [
            [DIGIT],
            [DIGIT, E, DIGIT],
            [DIGIT, E, SIGN, DIGIT],
            [DIGIT, POINT],
            [DIGIT, POINT, DIGIT],
            [DIGIT, POINT, DIGIT, E, DIGIT],
            [DIGIT, POINT, DIGIT, E, SIGN, DIGIT],
            [DIGIT, POINT, E, DIGIT],
            [DIGIT, POINT, E, SIGN, DIGIT],
            [POINT, DIGIT],
            [POINT, DIGIT, E, DIGIT],
            [POINT, DIGIT, E, SIGN, DIGIT],
            [SIGN, DIGIT],
            [SIGN, DIGIT, E, DIGIT],
            [SIGN, DIGIT, E, SIGN, DIGIT],
            [SIGN, POINT, DIGIT, E, SIGN, DIGIT],
            [SIGN, DIGIT, POINT],
            [SIGN, DIGIT, POINT, DIGIT],
            [SIGN, DIGIT, POINT, DIGIT, E, DIGIT],
            [SIGN, DIGIT, POINT, E, DIGIT],
            [SIGN, POINT, DIGIT],
            [SIGN, POINT, DIGIT, E, DIGIT]
        ]
        res = []
        for cur_s in s:
            cur_tag = None
            if cur_s in ["+", "-"]:
                cur_tag = SIGN
            elif cur_s in ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]:
                cur_tag = DIGIT
            elif cur_s == ".":
                cur_tag = POINT
            elif cur_s in ["E", "e"]:
                cur_tag = E
            if res:
                if res[-1] != cur_tag or cur_tag is POINT or cur_tag is E or cur_tag is SIGN:
                    res.append(cur_tag)
            else:
                res.append(cur_tag)
        return res in STATE

    def isNumber3(self, s: str) -> bool:
        """
            作废

        """
        # + - . E e 数值(N)
        N = ("0", "1", "2", "3", "4", "5", "6", "7", "8", "9")
        P = "."
        E = "E"
        ADD = "+"
        SUBSTRACT = "-"

        s = s.upper()

        states = {  # 记录一些可能性
            ("N",): 0,  # 2  0089  记录符合规范的下标     k 为数据的可能性  v 当前使用k的第几个内容  是数值 下标不变  不是 下标 + 1
            ("N", "."): 0,  # 4.           最终判断下标 = len(k) - 1
            ("N", "E", "N"): 0,  # 2e10
            ("N", "E", "+", "N"): 0,  # 3e+7
            ("N", ".", "E", "N"): 0,  # 46.e3
            ("N", ".", "N", "E", "N"): 0,  # 53.5e93
            ("+", "N"): 0,  # + 8
            ("+", ".", "N"): 0,  # +.8
            ("+", "N", ".", "N"): 0,  # +3.14
            ("+", "N", "E", "-", "N"): 0,  # +6e-1
            ("-", "N"): 0,
            ("-", "N", ".", "N", "E", "N"): 0,  # -123.456e789
            ("-", "N", ".", "N"): 0,  # -90E3
            ("-", "N", "E", "N"): 0,  # -8115e957
            ("-", ".", "N"): 0,  # -.9
            ("-", ".", "N", "E", "N"): 0,  # -.3e6
            ("-", "N", "."): 0,  # -1.
            ("-", "N", ".", "N"): 0,  # -0.1
            (".", "N"): 0,  # .1
            (".", "N", "E", "N"): 0,  # .0e7
        }

        # 1. 第一次进行初始化一下
        for k, v in states.items():
            if v == 0:  # 第一次
                if k[0] == "N" and s[0] in N:
                    states[k] = 1
                    continue
                if k[0] == "+" and s[0] == ADD:
                    states[k] = 1
                    continue
                if k[0] == "-" and s[0] == SUBSTRACT:
                    states[k] = 1
                    continue
                if k[0] == "." and s[0] == P:
                    states[k] = 1
                    continue
        # 2. 根据字符串的下标进行处理
        cur_index = 1
        # if s == "9E98+5403":
        #     print("---------")
        while cur_index < len(s):
            cur_ch = s[cur_index]
            for k, v in states.items():
                if v == 0:
                    continue
                if cur_ch in N:
                    if len(k) > v and k[v - 1] != "N" and k[v] == "N":
                        states[k] = v + 1
                elif cur_ch == E:
                    if len(k) > v and k[v - 1] != E and k[v] == E:
                        states[k] = v + 1
                    else:
                        states[k] = 0
                elif cur_ch == ADD:
                    if len(k) > v and k[v - 1] not in (ADD, SUBSTRACT) and k[v] == ADD:
                        states[k] = v + 1
                    else:
                        states[k] = 0
                elif cur_ch == SUBSTRACT:
                    if len(k) > v and k[v - 1] not in (ADD, SUBSTRACT) and k[v] == SUBSTRACT:
                        states[k] = v + 1
                    else:
                        states[k] = 0
                elif cur_ch == P:
                    if len(k) > v and k[v - 1] != P and k[v] == P:
                        states[k] = v + 1
                    else:
                        states[k] = 0
                else:
                    states[k] = 0
            # 检查cur_index 是否是最后一个 不是 则将匹配到ok的置为0
            if cur_index < len(s):
                for k, v in states.items():
                    if len(k) == v:
                        states[k] = 0

            cur_index += 1
        # print(s, {k: v for k, v in states.items() if len(k) == v + 1})
        for k, v in states.items():
            if len(k) == v:
                return True
        return False

    def isNumber2(self, s: str) -> bool:
        try:
            float(s)
            return True
        except Exception as e:
            return False

    def gen_rule(self, items=["32.e-80123", "+3.e04116", "-01", "0.8", ".1", "-8115e957", "-.3e6", "46.e3", ".0e7", "+.8", "-1.", "0", "2", "0089", "-0.1", "+3.14", "4.", "-.9", "2e10", "-90E3", "3e+7", "+6e-1", "53.5e93", "-123.456e789"]):
        items_res = set()

        for item in items:
            res = []
            for cur_s in item:
                cur_tag = None
                if cur_s in ["+", "-"]:
                    cur_tag = "SIGN"
                elif cur_s in ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]:
                    cur_tag = "DIGIT"
                elif cur_s == ".":
                    cur_tag = "POINT"
                elif cur_s in ["E", "e"]:
                    cur_tag = "E"
                if res:
                    if res[-1] != cur_tag:
                        res.append(cur_tag)
                else:
                    res.append(cur_tag)
            items_res.add(",".join(res))
        return sorted(items_res)


if __name__ == '__main__':
    s = Solution()
    print("-----------------------True-----------------------")
    # True
    for item in ["-.7e+0435", ".703e+4144", "1.38354e+8", "32.e-80123", "+3.e04116", "-01", "0.8", ".1", "-8115e957", "-.3e6", "46.e3", ".0e7", "+.8", "-1.", "0", "2", "0089", "-0.1", "+3.14", "4.", "-.9", "2e10", "-90E3", "3e+7", "+6e-1", "53.5e93", "-123.456e789"]:
        print("%s => %s" % (item, s.isNumber(s=item)))
    print("-----------------------False-----------------------")
    # False
    for item in ["..2", "9e98+5403", "e", ".", "abc", "1a", "1e", "e3", "99e2.5", "--6", "-+3", "95a54e53"]:
        print("%s => %s" % (item, s.isNumber(s=item)))
